<template>
  <div class="advanced-table-container">
    <div class="table-operations" v-if="$slots.toolbar">
      <slot name="toolbar"></slot>
    </div>

    <el-table
      ref="tableRef"
      v-loading="loading"
      :data="visibleData"
      :row-key="rowKey"
      :height="height"
      :max-height="maxHeight"
      :stripe="stripe"
      :border="border"
      :row-class-name="rowClassName"
      :highlight-current-row="highlightCurrentRow"
      @sort-change="handleSortChange"
      @selection-change="handleSelectionChange"
      @row-click="handleRowClick"
      @cell-click="handleCellClick"
      v-bind="$attrs"
    >
      <!-- 多选列 -->
      <el-table-column
        v-if="selection"
        type="selection"
        :width="selectionWidth"
        :fixed="selectionFixed"
        :selectable="selectable"
        align="center"
      />

      <!-- 序号列 -->
      <el-table-column
        v-if="showIndex"
        type="index"
        :index="indexMethod"
        :label="indexLabel"
        :width="indexWidth"
        :fixed="indexFixed"
        align="center"
      />

      <!-- 动态列渲染 -->
      <template v-for="column in columns" :key="column.prop">
        <!-- 普通列 -->
        <el-table-column
          v-if="!column.children || column.children.length === 0"
          :prop="column.prop"
          :label="column.label"
          :width="column.width"
          :min-width="column.minWidth"
          :fixed="column.fixed"
          :sortable="column.sortable"
          :show-overflow-tooltip="column.showOverflowTooltip !== false"
          :align="column.align || 'left'"
          :header-align="column.headerAlign || column.align || 'left'"
          :class-name="column.className"
          :span-method="column.spanMethod || spanMethod"
        >
          <template #default="scope">
            <!-- 使用作用域插槽 -->
            <slot
              :name="column.prop"
              :row="scope.row"
              :$index="scope.$index"
              :column="column"
            >
              {{ scope.row[column.prop] }}
            </slot>
          </template>

          <!-- 列头自定义 -->
          <template v-if="$slots[`header-${column.prop}`]" #header>
            <slot :name="`header-${column.prop}`"></slot>
          </template>
        </el-table-column>

        <!-- 多级表头 -->
        <el-table-column
          v-else
          :label="column.label"
          :align="column.align || 'left'"
          :header-align="column.headerAlign || column.align || 'left'"
          :class-name="column.className"
          :width="column.width"
          :min-width="column.minWidth"
          :fixed="column.fixed"
        >
          <template v-for="subColumn in column.children" :key="subColumn.prop">
            <el-table-column
              :prop="subColumn.prop"
              :label="subColumn.label"
              :width="subColumn.width"
              :min-width="subColumn.minWidth"
              :sortable="subColumn.sortable"
              :show-overflow-tooltip="subColumn.showOverflowTooltip !== false"
              :align="subColumn.align || column.align || 'left'"
              :header-align="
                subColumn.headerAlign ||
                subColumn.align ||
                column.align ||
                'left'
              "
              :class-name="subColumn.className"
              :span-method="subColumn.spanMethod || spanMethod"
            >
              <template #default="scope">
                <slot
                  :name="subColumn.prop"
                  :row="scope.row"
                  :$index="scope.$index"
                  :column="subColumn"
                >
                  {{ scope.row[subColumn.prop] }}
                </slot>
              </template>
            </el-table-column>
          </template>
        </el-table-column>
      </template>

      <!-- 默认插槽 -->
      <slot></slot>
    </el-table>

    <!-- 分页组件 -->
    <div class="pagination-container" v-if="pagination">
      <el-pagination
        v-model:current-page="currentPage"
        v-model:page-size="pageSize"
        :page-sizes="pageSizes"
        :total="total"
        :layout="paginationLayout"
        @size-change="handleSizeChange"
        @current-change="handleCurrentChange"
      />
    </div>
  </div>
</template>

<script lang="ts" setup>
import { ref, computed, watch, onMounted, nextTick } from 'vue'
import type { TableColumnCtx, TableInstance } from 'element-plus'
import Sortable from 'sortablejs'

// 类型定义
interface TableColumn {
  prop: string
  label: string
  width?: string | number
  minWidth?: string | number
  fixed?: boolean | 'left' | 'right'
  sortable?: boolean | 'custom'
  showOverflowTooltip?: boolean
  align?: 'left' | 'center' | 'right'
  headerAlign?: 'left' | 'center' | 'right'
  className?: string
  spanMethod?: (data: any) => number[] | undefined
  children?: TableColumn[]
}

// 定义组件Props
interface Props {
  // 表格数据源
  data: any[]
  // 表格列配置
  columns: TableColumn[]
  // 加载状态
  loading?: boolean
  // 行数据的Key，用于优化渲染
  rowKey?: string | ((row: any) => string)
  // 表格高度
  height?: string | number
  // 表格最大高度
  maxHeight?: string | number
  // 是否为斑马纹
  stripe?: boolean
  // 是否有边框
  border?: boolean
  // 是否显示多选框
  selection?: boolean
  // 多选框列宽
  selectionWidth?: string | number
  // 多选框是否固定
  selectionFixed?: boolean | 'left' | 'right'
  // 自定义行选中逻辑
  selectable?: (row: any, index: number) => boolean
  // 是否显示序号
  showIndex?: boolean
  // 序号列标题
  indexLabel?: string
  // 序号列宽度
  indexWidth?: string | number
  // 序号是否固定列
  indexFixed?: boolean | 'left' | 'right'
  // 自定义序号生成方法
  indexMethod?: (index: number) => number | string
  // 是否高亮当前行
  highlightCurrentRow?: boolean
  // 自定义行类名
  rowClassName?: string | ((param: { row: any; rowIndex: number }) => string)
  // 单元格合并方法
  spanMethod?: (data: {
    row: any
    column: TableColumnCtx<any>
    rowIndex: number
    columnIndex: number
  }) => number[] | { rowspan: number; colspan: number } | undefined
  // 分页相关
  pagination?: boolean
  pageSizes?: number[]
  paginationLayout?: string
  pageSize?: number
  currentPage?: number
  total?: number
  // 单页大小，用于虚拟滚动
  pageLimit?: number
  // 是否允许拖拽行
  rowDraggable?: boolean
  // 拖拽行的处理函数
  onRowDrop?: (from: number, to: number) => void
}

// 设置Props默认值
const props = withDefaults(defineProps<Props>(), {
  data: () => [],
  columns: () => [],
  loading: false,
  rowKey: 'id',
  height: undefined,
  maxHeight: undefined,
  stripe: true,
  border: true,
  selection: false,
  selectionWidth: 55,
  selectionFixed: 'left',
  selectable: undefined,
  showIndex: true,
  indexLabel: '序号',
  indexWidth: 80,
  indexFixed: 'left',
  indexMethod: undefined,
  highlightCurrentRow: false,
  rowClassName: '',
  spanMethod: undefined,
  pagination: true,
  pageSizes: () => [10, 20, 50, 100],
  paginationLayout: 'total, sizes, prev, pager, next, jumper',
  pageSize: 10,
  currentPage: 1,
  total: 0,
  pageLimit: 100,
  rowDraggable: false,
  onRowDrop: undefined,
})

// 定义事件
const emit = defineEmits([
  'update:currentPage',
  'update:pageSize',
  'page-change',
  'size-change',
  'selection-change',
  'sort-change',
  'row-click',
  'cell-click',
  'row-drop',
])

// 表格DOM引用
const tableRef = ref<TableInstance>()

// 虚拟滚动相关状态
const allData = computed(() => props.data)
const currentPage = ref(props.currentPage)
const pageSize = ref(props.pageSize)

// 可见数据计算属性，用于虚拟滚动
const visibleData = computed(() => {
  if (!props.pagination) {
    return allData.value
  }
  if (props.pageLimit && allData.value.length > props.pageLimit) {
    // 虚拟滚动模式，只显示一部分数据
    const start = (currentPage.value - 1) * pageSize.value
    return allData.value.slice(start, start + pageSize.value)
  }
  return allData.value
})

// 总数
const total = computed(() => props.total || allData.value.length)

// 分页事件处理
const handleSizeChange = (size: number) => {
  pageSize.value = size
  emit('update:pageSize', size)
  emit('size-change', size)
}

const handleCurrentChange = (page: number) => {
  currentPage.value = page
  emit('update:currentPage', page)
  emit('page-change', page)
}

// 表格事件处理
const handleSortChange = (params: any) => {
  emit('sort-change', params)
}

const handleSelectionChange = (selection: any[]) => {
  emit('selection-change', selection)
}

const handleRowClick = (row: any, column: any, event: Event) => {
  emit('row-click', row, column, event)
}

const handleCellClick = (
  row: any,
  column: any,
  cell: HTMLElement,
  event: Event
) => {
  emit('cell-click', row, column, cell, event)
}

// 单元格合并方法
const spanMethod = (data: {
  row: any
  column: TableColumnCtx<any>
  rowIndex: number
  columnIndex: number
}) => {
  return props.spanMethod?.(data)
}

// 实现行拖拽功能
const initRowDrag = () => {
  if (!props.rowDraggable || !tableRef.value) return

  const tbody = tableRef.value.$el.querySelector(
    '.el-table__body-wrapper tbody'
  )
  if (!tbody) return

  Sortable.create(tbody, {
    animation: 150,
    onEnd({ newIndex, oldIndex }) {
      if (newIndex === undefined || oldIndex === undefined) return
      if (typeof props.onRowDrop === 'function') {
        props.onRowDrop(oldIndex, newIndex)
      }
      emit('row-drop', { oldIndex, newIndex })
    },
  })
}

// 生命周期钩子
onMounted(() => {
  nextTick(() => {
    initRowDrag()
  })
})

// 监听数据变化
watch(
  () => props.data,
  () => {
    // 重新计算分页相关信息
    // 如果总页数变少了，且当前页超出了总页数，则重置为第一页
    const maxPage = Math.ceil(total.value / pageSize.value) || 1
    if (currentPage.value > maxPage) {
      currentPage.value = 1
      emit('update:currentPage', 1)
    }
  },
  { deep: true }
)

// 监听rowDraggable变化
watch(
  () => props.rowDraggable,
  (newVal) => {
    if (newVal) {
      nextTick(() => {
        initRowDrag() //行拖拽功能
      })
    }
  }
)

// 暴露给父组件的方法
defineExpose({
  tableRef,
  // 获取表格实例
  getTableInstance: () => tableRef.value,
  // 刷新表格
  refresh: () => {
    tableRef.value?.doLayout()
  },
})
</script>

<style scoped>
.advanced-table-container {
  width: 100%;
  display: flex;
  flex-direction: column;
}

.table-operations {
  margin-bottom: 16px;
}

.pagination-container {
  margin-top: 16px;
  display: flex;
  justify-content: flex-end;
}
</style>
